#include "swing.hpp"
#include "lines.hpp"
#include <cstdio>

namespace Trade {

void
Swing::reset() noexcept
{
  auto e_time = te;
  auto s_time = prev_stime;
  target.clear_reacheded();
  auto l = target.lines;
  memset((void*)(this), 0, sizeof(Swing));
  prev_etime = e_time;
  prev_stime = s_time;
  prev_lines = l;
}

void
Swing::set(const int64_t idx,
           const price_t hp_now,
           const time_t t_now,
           const Lines& lines) noexcept
{
  this->idx = idx;
  this->hpx = hp_now;
  ts = t_now;
  te = t_now + 3600 + 1800;
  target.set_timer(te, 0);

  if (prev_etime && t_now - prev_etime < ONE_HALF_HOUR &&
      t_now - prev_stime < (AN_HOUR * 4)) {
    // target.update_lines(1, prev_lines, hp_now);
    // target.update_lines(-1, prev_lines, hp_now);
    target.set_lines(prev_lines);
  } else {
    // target.update_lines(1, lines, hp_now);
    // target.update_lines(-1, lines, hp_now);
    target.set_lines(lines);
    prev_stime = ts;
    prev_etime = 0;
  }
  swing = true;
  prev_etime = 0;
}

int8_t
Swing::update_lines(const Lines& lines, const price_t hp_now) noexcept
{
  auto up = target.update_lines(1, lines, hp_now);
  auto dn = target.update_lines(-1, lines, hp_now);

  int8_t ret = 0;
  if (up && dn)
    ret = 2;
  else if (up)
    ret = 1;
  else if (dn)
    ret = -1;
  return ret;
}

void
Swing::print(const time_t t_now, const price_t hp_now) const noexcept
{
  if (swing) {
    printf("(((( \033[38;5;001m Swing %d mins\033[0m dir %d )))) _____________\n",
           int(target.timer.t - t_now) / 60,
           dir_swing);
    target.lines.print(0, hp_now);
  }
}

uint8_t
Swing::reached(const time_t t_now,
               const price_t hp_now,
               Lines& l_now,
               const int64_t idx) noexcept
{
  uint8_t rchd = 0;
  rchd |= target.check_reached(t_now, hp_now, l_now, idx);
  return rchd;
}

uint8_t
Swing::reacheded() noexcept
{
  return target.reached;
}

void
Swing::clear_reacheded() noexcept
{
  target.reached = 0;
}

bool
Swing::reached_line2(const dir_t dir) noexcept
{
  bool rchd = false;
  if (dir > 0) {
    rchd = (target.lines.nup > 1 && (target.reached & LIMIT_REACHED::REACHED_UP_2));
  } else {
    rchd = (target.lines.ndn > 1 && (target.reached & LIMIT_REACHED::REACHED_DN_2));
  }
  return rchd;
}

bool
Swing::reached_line1(const dir_t dir) noexcept
{
  bool rchd = 0;
  if (dir > 0) {
    rchd = (target.lines.nup > 0 &&
            target.reached & (LIMIT_REACHED::REACHED_UP_1 | LIMIT_REACHED::REACHED_UP_2));
  } else {
    rchd = (target.lines.ndn > 0 &&
            target.reached & (LIMIT_REACHED::REACHED_DN_1 | LIMIT_REACHED::REACHED_DN_2));
  }
  return rchd;
}

bool
Swing::timer_outed() noexcept
{
  return (target.reached & LIMIT_REACHED::REACHED_TIMER_OUT);
}

void
Swing::update_timer(const time_t tm) noexcept
{
  target.update_timer(tm, 0);
}

bool
Swing::set_swing_dir(const uint8_t rchd) noexcept
{
  bool s_up = false, s_dn = false;
  bool changed = false;
  if (rchd) {
    if (rchd & LIMIT_REACHED::REACHED_DN_1 || rchd & LIMIT_REACHED::REACHED_DN_2)
      s_dn = true;
    if (rchd & LIMIT_REACHED::REACHED_UP_1 || rchd & LIMIT_REACHED::REACHED_UP_2)
      s_up = true;

    dir_t d = 0;
    if (s_up && s_dn) {
      // so wired
    } else if (s_up) {
      d = -1;
    } else if (s_dn) {
      d = 1;
    }

    if (dir_swing != d) {
      changed = true;
      dir_swing = d;
    }
  }

  return changed;
}

} // namespace Trade